/**************************************************************************
 * @file serial_protocol.h
 * @author BryanHe(贺璧) (532352406@qq.com)
 * @brief 
 * @version 0.1
 * @date 2025-04-07
 * 
 * @copyright Copyright (c) 2025
 * 
 *************************************************************************/
#ifndef USR_SERIAL_PROTOCOL__H_H
#define USR_SERIAL_PROTOCOL__H_H

#ifdef __cplusplus
extern "C"{
#endif
#include<stdint.h>
#include<stdio.h>
#include "data_pack_handle.h"

#define SERIAL_PROTOCOL_VERSION "V1.1"

#define SERIAL_PROTOCOL_DEBUG_EN 0


//------------------- 协议层配置 -------------------
#define MAX_RETRY_TIMES  3ul
#define ACK_TIMEOUT_MS   100ul

//------------------- 协议定义 -------------------
typedef enum {
    CMD_UNKNOWN = 0x00,
    CMD_ACK_INFO,
    CMD_GET_INFO,
    CMD_SET_CONFIG,
    // 用户可在此添加自定义命令码
    CMD_USER_START,

} CommandCode;

typedef enum {
    STATUS_SUCCESS = 0x00,
    STATUS_INVALID_CMD,
    STATUS_CRC_ERROR,
    STATUS_WAIT_ACK_TIMEOUT,
    // 用户可在此添加自定义状态码
    STATUS_USER_START,

} CommandStatus;

//------------------- 用户语义接口 -------------------
typedef struct {
    CommandCode code;
    CommandStatus (*handler)(const uint8_t* params, uint8_t len, uint8_t* response,uint16_t *response_len);
} UserCommand;

#define FORMAT_USR_CMD_CODE(cmd)   ((CommandCode)cmd)
#define FORMAT_USR_CMD_ITEM(cmd)   {.code = FORMAT_USR_CMD_CODE(cmd), .handler = _##cmd##_handle}
#define USR_CMD_FUN_NAME_MAKE(cmd) _##cmd##_handle

typedef int (*serial_send)(uint8_t *p_buf,uint16_t send_len);
typedef void (*serial_ack_cb)(CommandCode cmd, CommandStatus status,const uint8_t* params, uint8_t len);

//------------------- 通信时序核心 -------------------
typedef struct {
    // 发送缓冲区
    uint8_t tx_buffer[USR_D_PACK_MAX_PACKAGE_LEN];
    uint32_t last_packet_len;
    serial_send s_send_handle;
    serial_ack_cb ack_status_cb;
    CommandCode last_send_cmd;

    // 接收缓冲区
    uint8_t rx_buffer[USR_D_PACK_MAX_PACKAGE_LEN];
    uint8_t rx_process_buf[USR_D_PACK_MAX_PACKAGE_LEN];
    uint16_t rx_index;
    uint8_t rx_pkg_len;

    // 超时计数器
    uint32_t last_send_time;
    uint8_t retry_count;

    const UserCommand *p_cmd_table;
    uint16_t cmd_table_size;

    uint32_t serial_p_tick; /*the interval should be 1mS*/
    // 当前事务状态
    uint8_t waiting_ack;
    uint32_t tick_interval;

} ProtocolHandler;

void print_buffer_raw(const uint8_t *buf, uint32_t len);
void serial_protocol_processing(ProtocolHandler *handler);//it Should be invoked in 1mS loop
void serial_protocol_receive(ProtocolHandler *handler, uint8_t *p_buf, uint16_t len);
void serial_protocol_send(ProtocolHandler *handler, uint8_t *cmd_buf, uint8_t cmd_len,serial_ack_cb ack_cb);
void serial_protocol_init(ProtocolHandler *handler,const UserCommand *p_cmd_table,uint16_t cmd_table_size,serial_send s_send_handle,uint32_t tik_interval);


#if SERIAL_PROTOCOL_DEBUG_EN
// #define SP_LOG(format, ...) printf("File: %s, Line: %d: " format "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define SP_LOG(format, ...) printf(format, ##__VA_ARGS__)
// #define SP_LOG(format, ...) printf(format __VA_OPT__(,) __VA_ARGS__)
// #define SP_LOG(format) printf(format)
#define SP_LOG_RAW(buf,size) print_buffer_raw(buf, size)
#else
#define SP_LOG(format, ...) 
#define SP_LOG_RAW(buf,size)
#endif


#ifdef __cplusplus
}
#endif

#endif //USR_SERIAL_PROTOCOL__H_H


